/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/* 
 * File:   fltkrecoder.cpp
 * Author: Administrator
 * 
 * Created on 2021年3月5日, 下午3:11
 */

#include "fltkrecoder.h"
static void _reset_callback(Fl_Widget *w, void *data) {
	Fl_File_Input*p=(Fl_File_Input*)data;
	p->value("");	
}
static void _loadwav_callback(Fl_Widget *w, void *data) {
	fltkrecoder*p=(fltkrecoder*)data;
	p->loadwav_callback();	
}
static void _startrecoder_callback(Fl_Widget *w, void *data) {
	fltkrecoder*p=(fltkrecoder*)data;
	p->startrecoder_callback();	
}
static void _sdl_play_audio_callback(void *userdata, Uint8 *stream, int len){
    fltkrecoder*p=(fltkrecoder*)userdata;
	p->playaudiobuff(stream,len);
}
static void _stoprecoder_callback(Fl_Widget *w, void *data) {
	fltkrecoder*p=(fltkrecoder*)data;
	p->stoprecoder_callback();	
}

static void _playrecoder_callback(Fl_Widget *w, void *data) {
	fltkrecoder*p=(fltkrecoder*)data;
	p->playrecoder_callback();	
}
static void _sdl_recoder_audio_callback(void *userdata, Uint8 *stream, int len){
    fltkrecoder*p=(fltkrecoder*)userdata;
	p->recoderaudiobuff(stream,len);
}
fltkrecoder::fltkrecoder()
{
	m_speed=1.0;
	m_audiotype=0;
	m_audiobuff=NULL;
	m_audiobuff_buffsize=0;
	m_audiobuff_playsize=0;
	m_audiobuff_recodersize=0;
}

fltkrecoder::~fltkrecoder()
{
}
void fltkrecoder::init(){
	m_window = new Fl_Window(800,220,"录音机");
	m_capturedevicelist=new Fl_Choice(60,10,100,40,"录音设备");
	m_playdevicelist=new Fl_Choice(230,10,100,40,"播放设备");
	m_driverlist=new Fl_Choice(400,10,100,40,"设备驱动");
	
	m_recordeaudiobutton = new Fl_Button(510, 10, 80, 40, "Recoder");
	m_recordeaudiobutton->type(FL_NORMAL_BUTTON);
	m_recordeaudiobutton->callback(_startrecoder_callback,(void*)this);
	
	m_stopaudiobutton = new Fl_Button(600, 10, 80, 40, "Stop");
	m_stopaudiobutton->type(FL_NORMAL_BUTTON);
	m_stopaudiobutton->callback(_stoprecoder_callback,(void*)this);
	
	m_playaudiobutton = new Fl_Button(690, 10, 80, 40, "Play");
	m_playaudiobutton->type(FL_NORMAL_BUTTON);
	m_playaudiobutton->callback(_playrecoder_callback,(void*)this);
	
	m_speedlist=new Fl_Choice(60,60,100,40,"声音变速");
	m_audiotypelist=new Fl_Choice(230,60,100,40,"声音变形");
	
	m_speedlist->add("0.5");
	m_speedlist->add("1.0");
	m_speedlist->add("1.25");
	m_speedlist->add("1.5");
	m_speedlist->add("2.0");
	m_speedlist->value(1);
	
	m_audiotypelist->add("正常");
	m_audiotypelist->add("男声");
	m_audiotypelist->add("女声");
	m_audiotypelist->value(0);
	
	m_fileinput=new Fl_File_Input(60, 100, 480, 40, "Wav文件");
	m_resetbutton=new Fl_Button(550, 100, 80, 40, "重置");
	m_resetbutton->type(FL_NORMAL_BUTTON);
	m_resetbutton->callback(_reset_callback,(void*)m_fileinput);
	m_loadwavbutton= new Fl_Button(640, 100, 80, 40, "加载");
	m_loadwavbutton->type(FL_NORMAL_BUTTON);
	m_loadwavbutton->callback(_loadwav_callback,(void*)this);
	
	m_window->end();
	m_window->show();
	reflashdevicelist();
}
void fltkrecoder::uninit(){
}
void fltkrecoder::reflashdevicelist(){
	int n = SDL_GetNumAudioDevices(0);
	int i=0;
	m_playdevicelist->clear();
	for (i = 0; i < n; i++) {
        printf("%d PlayDevice %s\n",i, SDL_GetAudioDeviceName(i, 0));
		m_playdevicelist->add(SDL_GetAudioDeviceName(i, 0));
    }
	m_playdevicelist->value(0);
	n = SDL_GetNumAudioDevices(1);
	m_capturedevicelist->clear();
	for (i = 0; i < n; i++) {
        printf("%d CaptureDevice %s\n",i, SDL_GetAudioDeviceName(i, 1));
		m_capturedevicelist->add(SDL_GetAudioDeviceName(i, 1));
    }
	m_capturedevicelist->value(0);
	m_driverlist->clear();
	for (i = 0; i < SDL_GetNumAudioDrivers(); ++i) {
		printf("Audio driver %d: %s\n", i, SDL_GetAudioDriver(i));
		m_driverlist->add(SDL_GetAudioDriver(i));
	}
	m_driverlist->value(0);
}
void fltkrecoder::loadwav_callback(){
	if(m_fileinput->value()!=NULL){
		if(m_audiobuff){
			SDL_free(m_audiobuff);
			m_audiobuff=NULL;
			m_audiobuff_buffsize=0;
		}		
		SDL_LoadWAV(m_fileinput->value(),&m_wavspec,(Uint8**)&m_audiobuff,(Uint32*)&m_audiobuff_buffsize);
		//一律转换为统一格式
		SDL_AudioCVT cvt;
		SDL_BuildAudioCVT(&cvt,m_wavspec.format,m_wavspec.channels,m_wavspec.freq,AUDIO_F32,2,44100);
		cvt.buf=(Uint8*)SDL_realloc((void*)m_audiobuff,m_audiobuff_buffsize*cvt.len_mult);
		cvt.len=m_audiobuff_buffsize;
		SDL_ConvertAudio(&cvt);
		
		m_wavspec.format=AUDIO_F32;
		m_wavspec.channels=2;
		m_wavspec.freq=44100;
		m_audiobuff_buffsize=cvt.len_cvt;
		m_audiobuff=(char*)cvt.buf;
		m_audiobuff_playsize=0;
		m_audiobuff_recodersize=m_audiobuff_buffsize;
		printf("loadwav_callback:buffsize:%d samples:%hu %p %p %s\n",m_audiobuff_buffsize,m_wavspec.samples,
		cvt.buf,m_audiobuff,SDL_GetError());
	}
}
void fltkrecoder::startrecoder_callback(){
	SDL_AudioSpec have={0};
	m_wavspec.callback=_sdl_recoder_audio_callback;
	m_wavspec.freq=44100;
	m_wavspec.samples=4096;
	m_wavspec.channels=2;
	m_wavspec.format=AUDIO_F32;
	m_wavspec.userdata=this;
	if(m_audiobuff){
		SDL_free(m_audiobuff);
		m_audiobuff=NULL;
		m_audiobuff_buffsize=0;
	}
	m_audiobuff_buffsize=44100*2*32*10/8;
	m_audiobuff_playsize=0;
	m_audiobuff_recodersize=0;
	m_audiobuff=(char*)SDL_malloc(m_audiobuff_buffsize);
	m_audiodev=SDL_OpenAudioDevice(NULL, 1, &m_wavspec, &have, SDL_AUDIO_ALLOW_FORMAT_CHANGE);
	SDL_PauseAudioDevice(m_audiodev,0);
	printf("startrecoder_callback:%d %s\n",m_audiodev,SDL_GetError());
}
void fltkrecoder::stoprecoder_callback(){
	if(m_audiodev>0){
		printf("stoprecoder_callback:%d buff:%d recoder:%d play:%d %s\n",m_audiodev,
			m_audiobuff_buffsize,m_audiobuff_recodersize,m_audiobuff_playsize,SDL_GetError());
		SDL_PauseAudioDevice(m_audiodev,1);
		SDL_CloseAudioDevice(m_audiodev);
		m_audiodev=0;
		m_audiobuff_playsize=0;
	}
}
void fltkrecoder::playrecoder_callback(){
	SDL_AudioSpec want={0},have={0};
	m_speed=atof(m_speedlist->text());
	m_audiotype=m_audiotypelist->value();
	want.callback=_sdl_play_audio_callback;
	//修改速度,这个方法不太好,这么改会变调
	//want.freq=m_wavspec.freq*m_speed;
	want.freq=m_wavspec.freq;
	want.samples=m_wavspec.samples;
	want.channels=m_wavspec.channels;
	want.format=m_wavspec.format;
	want.userdata=this;
	m_audiodev=SDL_OpenAudioDevice(NULL, 0, &want, &have, SDL_AUDIO_ALLOW_FORMAT_CHANGE);	
	m_soundTouch.setSampleRate(want.freq);
    m_soundTouch.setChannels(want.channels);
	//会变调
	//m_soundTouch.setRate(m_speed);
	m_soundTouch.setTempo(m_speed);
	int speech=0;
	if(speech){
		m_soundTouch.setSetting(SETTING_SEQUENCE_MS, 40);
        m_soundTouch.setSetting(SETTING_SEEKWINDOW_MS, 15);
        m_soundTouch.setSetting(SETTING_OVERLAP_MS, 8);
	}
	SDL_PauseAudioDevice(m_audiodev,0);
}

void fltkrecoder::playaudiobuff(void *stream,int len){
	if(m_audiobuff_playsize<m_audiobuff_recodersize){
		int reallen=len;
		if(reallen>(m_audiobuff_recodersize-m_audiobuff_playsize)){
			reallen=m_audiobuff_recodersize-m_audiobuff_playsize;
		}
		memcpy(stream,m_audiobuff+m_audiobuff_playsize,reallen);		
		m_audiobuff_playsize+=reallen;
	}else{
		stoprecoder_callback();
	}	
}
void fltkrecoder::recoderaudiobuff(void *stream,int len){
	if((m_audiobuff_recodersize+len)<m_audiobuff_buffsize){
		memcpy(m_audiobuff+m_audiobuff_recodersize,stream,len);
		m_audiobuff_recodersize+=len;
	}else{
		stoprecoder_callback();
	}
}